#include <iostream>
#include <unistd.h>
#include <fcntl.h>
#include <cstdio>
#include <cerrno>
#include <cstring>
using namespace std;

void SetNonBlock(int fd)
{
    // stuct文件结构体中有许多文件的属性，fcntl就是获取这个结构体的某个标志位（属性）的值
    int f1 = fcntl(fd, F_GETFL); // 这行代码的功能是记录文件本来就有的标志位（防止调用第二个fcntl后丢失）
    if (f1 < 0)
    {
        perror("fcntl");
        return;
    }
    // 设置文件状态，f1是老的文件标志位，按位或上非阻塞阻塞标志位（有1则1，全0才0）
    fcntl(fd, F_SETFL, f1 | O_NONBLOCK); // 这里按位或是把老的选项和非阻塞选项组合成一个新的选项
    cout << "set" << fd << "nonblock success" << endl;
}
int main()
{
    char buffer[1024];
    SetNonBlock(0); // 把0文件描述符设置为非阻塞
    while (true)
    {
        // printf("请输入内容#");
        // fflush(stdout);
        //  从标准输入（0文件描述符）中读取，存储到buffer里，-1是不当字符串处理
        ssize_t n = read(0, buffer, sizeof(buffer) - 1); // 由于设置了非阻塞，read读不到数据会立即返回
        if (n > 0)
        {
            buffer[n - 1] = 0; // 结尾添\n
            cout << "读取到的内容是：" << buffer << endl;
        }
        else if (n == 0) // 读出错和读取完成是两回事
        {
            cout << "读取完成" << endl;
            break;
        }
        else
        {
            // 1.设置为非阻塞，如果底层fd数据没有就绪，recv/read/write/send，返回值会以出错的形式返回
            // 2.返回有两种情况 a.真的出错 b.底层数据没有就绪
            // 3.如何区分，通过errno区分
            // 读取不到数据，OS返回EWOULDBLOCK，这个宏的意思是，我没问题，请再试一次
            if (errno == EWOULDBLOCK)
            {
                cout << "出错的原因是，数据未就绪" << endl;
                sleep(1);
            }
            else
            {
                cerr << "读取失败 n=" << n << " errno number:" << errno << " errno str: " << strerror(errno) << endl;
                cerr << "开始轮询，检测下一轮条件是否就绪" << endl;
            }
        }
    }
    return 0;
}